package gui;

import java.util.Vector;

import javax.swing.table.TableModel;
import javax.swing.event.TableModelEvent;

//////////////////////////////////////////////////////////////////////////
//// TableSorter
/**

@author Ivan Jeukens
@version v 0.1 11/10/2002
*/
public class TableSorter extends TableMap {

    public TableSorter(TableModel model) {
        setModel(model);
    }

    public int indexes[];
    public Vector sortingColumns = new Vector();
    public boolean ascending = true;
    public int compares;

    ///////////////////////////////////////////////////////////////////
    ////                         public methods                    ////

    public void setModel(TableModel model) {
        super.setModel(model);
        reallocateIndexes();
    }

    public int compareRowsByColumn(int row1, int row2, int column) {
        Class type = _model.getColumnClass(column);
        TableModel data = _model;

        Object o1 = data.getValueAt(row1, column);
        Object o2 = data.getValueAt(row2, column); 

        if(o1 == null && o2 == null) {
            return 0; 
        } 
	else
	if(o1 == null) { 
            return -1; 
        } 
	else 
	if(o2 == null) { 
            return 1; 
        }
	
	int result = 0;
	if(type == String.class) {
            String s1 = (String) data.getValueAt(row1, column);
            String s2 = (String) data.getValueAt(row2, column);
            result = s1.compareTo(s2);
	}
	else
	if(type == Double.class) {
            Double d1 = (Double) data.getValueAt(row1, column);
            Double d2 = (Double) data.getValueAt(row2, column);
            result = d1.compareTo(d2);
	}
	else
	if(type == Integer.class) {
	    Integer l1 = (Integer) data.getValueAt(row1, column);
	    Integer l2 = (Integer) data.getValueAt(row2, column);
	    result = l1.compareTo(l2);
	}
        
	if(result < 0) {
            return -1;
        }
	else
	if(result > 0) {
            return 1;
        }
        return 0;
    }

    public int compare(int row1, int row2) {
        compares++;
        for (int level = 0; level < sortingColumns.size(); level++) {
            Integer column = (Integer)sortingColumns.elementAt(level);
            int result = compareRowsByColumn(row1, row2, column.intValue());
            if (result != 0) {
                return ascending ? result : -result;
            }
        }
        return 0;
    }

    public void reallocateIndexes() {
        int rowCount = _model.getRowCount();

        indexes = new int[rowCount];
        for (int row = 0; row < rowCount; row++) {
            indexes[row] = row;
        }
    }

    public void tableChanged(TableModelEvent e) {
        reallocateIndexes();
        super.tableChanged(e);
    }

    public void checkModel() {
        if(indexes.length != _model.getRowCount()) {
            System.err.println("Sorter not informed of a change in model.");
        }
    }

    public void sort(Object sender) {
        checkModel();
        compares = 0;
        shuttlesort((int[])indexes.clone(), indexes, 0, indexes.length);
    }

    public void n2sort() {
        for (int i = 0; i < getRowCount(); i++) {
            for (int j = i+1; j < getRowCount(); j++) {
                if (compare(indexes[i], indexes[j]) == -1) {
                    swap(i, j);
                }
            }
        }
    }

    public void shuttlesort(int from[], int to[], int low, int high) {
        if (high - low < 2) {
            return;
        }
        int middle = (low + high)/2;
        shuttlesort(to, from, low, middle);
        shuttlesort(to, from, middle, high);

        int p = low;
        int q = middle;

        if (high - low >= 4 && compare(from[middle-1], from[middle]) <= 0) {
            for (int i = low; i < high; i++) {
                to[i] = from[i];
            }
            return;
        }

        for (int i = low; i < high; i++) {
            if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
                to[i] = from[p++];
            }
            else {
                to[i] = from[q++];
            }
        }
    }

    public void swap(int i, int j) {
        int tmp = indexes[i];
        indexes[i] = indexes[j];
        indexes[j] = tmp;
    }

    public Object getValueAt(int aRow, int aColumn) {
        checkModel();
        return _model.getValueAt(indexes[aRow], aColumn);
    }

    public void setValueAt(Object aValue, int aRow, int aColumn) {
        checkModel();
        _model.setValueAt(aValue, indexes[aRow], aColumn);
    }

    public void sortByColumn(int column) {
        this.ascending = true;
        sortingColumns.removeAllElements();
        sortingColumns.addElement(new Integer(column));
        sort(this);
        super.tableChanged(new TableModelEvent(this)); 
    }

    ///////////////////////////////////////////////////////////////////
    ////                        private methods                    ////
    
    ///////////////////////////////////////////////////////////////////
    ////                       private variables                    ////
    
}
